//
//  YFRefreshControl.swift
//  仿新浪微博
//
//  Created by 杨帆 on 16/7/8.
//  Copyright © 2016年 杨帆. All rights reserved.
//

import UIKit

// 刷新状态切换的临界点
private let YFRefreshOffset: CGFloat = 126

// 刷新状态
// - Normal:      普通状态，什么都不做
// - Pulling:     超过临界点，如果放手，开始刷新
// - WillRefresh: 用户超过临界点，并且放手
enum YFrefreshState {

    case Normal
    case Pulling
    case WillRefresh
}


// 刷新控件 - 负责刷新相关的逻辑处理
class YFRefreshControl: UIControl {
    
    // MARK: - 属性
    //下拉刷新控件应该适用于 UITableView / UICollectionView
    private weak var scrollView: UIScrollView?
    
    // 刷新视图
    private lazy var refreshView: YFRefreshView = YFRefreshView.refreshView()
    
    // MARK: - 构造函数
    init() {
        super.init(frame: CGRect())
        
        setupUI()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        setupUI()
    }
    
    /*
     willMove addSubview 方法会调用
     - 当添加到父视图的时候，newSuperview 是父视图
     - 当父视图被移除，newSuperview 是 nil
     */

    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: newSuperview)
        
        // 判断父视图的类型
        guard let sv = newSuperview as? UIScrollView else {
        
            return
        }
        
        // 记录父视图
        scrollView = sv
        
        // KVO监听父视图的contentOffset
        scrollView?.addObserver(self, forKeyPath: "contentOffset", options: [], context: nil)
    }
    
    // 所有KVO 方法会同意调用此方法
    // 本视图从父视图上移除
    override func removeFromSuperview() {
        // superView 还存在
        superview?.removeObserver(self, forKeyPath: "contentOffset")
        
        super.removeFromSuperview()
        
        // superView 不存在
    }
    
    // 所有 KVO 方法会统一调用此方法
    // 在程序中，通常只监听某一个对象的某几个属性，如果属性太多，方法会很乱！
    // 观察者模式，在不需要的时候，都需要释放
    // - 通知中心：如果不释放，什么也不会发生，但是会有内存泄漏，会有多次注册的可能！
    // - KVO：如果不释放，会崩溃！

    override func observeValue(forKeyPath keyPath: String?, of object: AnyObject?, change: [NSKeyValueChangeKey : AnyObject]?, context: UnsafeMutablePointer<Void>?) {
        
        guard let sv = scrollView else {
            return
        }
        
        // 初始高度就应该是 0 
        let height = -(sv.contentInset.top + sv.contentOffset.y)
        
        if height < 0 {
        
            return
        }
        
        // 可以根据高度设置刷新控件的 frame
        self.frame = CGRect(x: 0,
                            y: -height,
                            width: sv.bounds.width,
                            height: height)
        
        // 传递父视图高度 如果正在刷新中 不传递
        if refreshView.refreshState != .WillRefresh {
            refreshView.parentViewHeight = height

        }
        
        // 判断临界点  - 只需要判断一次
        if sv.isDragging {
        
            if height > YFRefreshOffset && (refreshView.refreshState == .Normal) {
            
                print("放手刷新")
                
                refreshView.refreshState = .Pulling
            }
        } else if height <= YFRefreshOffset && (refreshView.refreshState == .Pulling){
            
            print("继续使劲..")
            refreshView.refreshState = .Normal
        
        } else {
            
            // 放手 -  判断是否超过临界点
            if refreshView.refreshState == .Pulling {
            
                print("准备开始刷新")
                
                // 调用开始刷新方法
                beginRefreshing()
                
                // 发送刷新数据事件
                sendActions(for: .valueChanged)
            }
        }
    }

    // 开始刷新
    func beginRefreshing() {
    
        print("开始刷新")
        
        // 判断父视图
        guard let sv = scrollView else {
        
            return
        }
        // 判断是否正在刷新如果是 直接返回
        if refreshView.refreshState == .WillRefresh {
            return
        }
        
        // 设置刷新状态
        refreshView.refreshState = .WillRefresh
        

        
        // 设置表格的间距
        var inset = sv.contentInset
        
        inset.top += YFRefreshOffset
        

        sv.contentInset = inset
        
         //设置刷新视图的父视图高度
        refreshView.parentViewHeight = YFRefreshOffset
        
        // 如果开始调用 beginRefresh 会重复发送刷新事件
        //sendActions(for: .valueChanged)
    }
    
    // 结束刷新
    func endRefreshing() {
     
        print("结束刷新")
        
        guard let sv = scrollView else {
        
            return
        }
        
        // 判断状态是否在刷新 不是直接返回
        if refreshView.refreshState != .WillRefresh {
         
            return
        }
        
        // 恢复刷新视图的状态
        refreshView.refreshState = .Normal
        
        // 恢复表格视图的 cuntentInset
        var inset = sv.contentInset
        inset.top -= YFRefreshOffset
        
        sv.contentInset = inset
    }

}

extension YFRefreshControl {

    private func setupUI() {
    
        backgroundColor = superview?.backgroundColor
        
        // 设置超出边界不显示
//        clipsToBounds = true
        
        // 添加刷新视图 从xib加载出来 默认是xib 中指定的宽高

        addSubview(refreshView)
        
        // 自动布局 原生写法
        refreshView.translatesAutoresizingMaskIntoConstraints = false
        
        addConstraint(NSLayoutConstraint(item: refreshView,
                                         attribute: .centerX,
                                         relatedBy: .equal,
                                         toItem: self,
                                         attribute: .centerX,
                                         multiplier: 1.0,
                                         constant: 0))
        
        addConstraint(NSLayoutConstraint(item: refreshView,
                                         attribute: .bottom,
                                         relatedBy: .equal,
                                         toItem: self,
                                         attribute: .bottom,
                                         multiplier: 1.0,
                                         constant: 0))
        
        addConstraint(NSLayoutConstraint(item: refreshView,
                                         attribute: .width,
                                         relatedBy: .equal,
                                         toItem: nil,
                                         attribute: .notAnAttribute,
                                         multiplier: 1.0,
                                         constant: refreshView.bounds.width))
        
        addConstraint(NSLayoutConstraint(item: refreshView,
                                         attribute: .height,
                                         relatedBy: .equal,
                                         toItem: nil,
                                         attribute: .notAnAttribute,
                                         multiplier: 1.0,
                                         constant: refreshView.bounds.height))

    }
}
